'''
    The model module implements saving & loading to and from a single
    file archive. It uses tarfile.
    
    You can start adding XML, dicom etc immediately, it will be added to a temp file.
    If you don't call SetSavePath at least once before the object is destroyed, the tempfile
    will be deleted.
    
    You can only load something if you have saved it first or set the savePath to point to a
    valid archive using SetSavePath
    
    @author: S.G. Epskamp
    @organization: Twente University

'''
import os, wx, tarfile, shutil, tempfile
class ArchiveSaver:
    def __init__(self):
        '''
            The constructor, create a default temp file to save in
        '''  
        self._CreateTempFile()
        self.programPath = os.getcwd()
        
    def __del__(self):
        '''
            Destructor, if we're still working in a temp file: remove it.
        '''
        self._ClearTemp()
    
    def SetSavePath(self, path):
        '''
            Set the path to the file that should be used for saving & loading.
            
            @param path: path to file, e.g. /home/simon/klaasjan.hdt
        '''
        # copy old file to new location, if it was created yet
        if os.path.exists(self.savePath):
            shutil.copy(self.savePath, path)
        self._ClearTemp()
        self.savePath = path
        self.temp = False
        
    def SaveXML(self, XML):
        '''
            Save XML describing state to archive
            
            @param XML: String containing xml to be saved
        '''
        # save xml to data.xml in current dir, and put in tarfile
        # dont use os.tmpfile, cause you'll end up in a world of hurt
        tmpXmlPath = os.path.join(self.programPath,'tmp','data.xml')
        open(tmpXmlPath, 'w').write(XML)
        self._AddToSaveFile(tmpXmlPath, 'data.xml')
        os.unlink(tmpXmlPath)
    
    def LoadXML(self):
        '''
            Try to load XML from file at current savePath
            
            @return: String, nothing if loading failed
        '''
        return self._File2String('data.xml')
    
    def AddDicom(self, path):
        '''
            add dicom data to save file
        '''
        self._AddToSaveFile(path, 'dicom')
    
    def LoadDicom(self):
        '''
            Load dicom files from tar file
            they are extracted to self.programPath/tmp/dicom, for you
            to do what you want with them.
            If there are files there already, they are deleted.
            
            @return: boolean, indicating if loading was successful
        '''    
        # open tarfile for reading
        tf = tarfile.open(self.savePath, 'r')
        if self._SaveHasFile('dicom/'):
            # gather dicom files from tar file
            infos = []
            for name in tf.getnames():
                if(name[:5] == 'dicom'):
                    infos.append(tf.getmember(name))
                    
            try:
                # remove old files first
                if(os.path.exists( os.path.join(self.programPath,'tmp','dicom') )):
                    shutil.rmtree( os.path.join(self.programPath,'tmp','dicom') )
                tf.extractall( os.path.join(self.programPath,'tmp'), infos )
                tf.close()
                return True
            except IOError:
                print 'problems were encountered while removing old dicom files, dicom not loaded'
                tf.close()
                return False
        else:
            print 'save file doesn\'t contain dicom data'
         
    def HasDicom(self):
        '''
            Does the savefile contain dicom data?
        '''
        return self._SaveHasFile('dicom/')
    
    def AddRecording(self, data, filename):
		'''
			Add a recording to the savefile
			
			@param data: string describing the recording
			@param filename: filename to be used in archive
		'''
		tmpDataPath = os.path.join(self.programPath,'tmp',filename)
		print tmpDataPath
		print data
		path = str(tmpDataPath)
		open(path, 'w').write(data)
		self._AddToSaveFile(tmpDataPath, 'rec/'+filename)
		os.unlink(tmpDataPath)
		print 'recording added'
    
    def ListRecordings(self):
        '''
            List all recordings in savefile
            
            @return: array containing filenames of all recordings
        '''
        # open tarfile for reading
        tf = tarfile.open(self.savePath, 'r')
        recordings = []
        for name in tf.getnames():
            if(name[:3] == 'rec'):
                recordings.append(name)
        tf.close()
        return recordings
    
    def LoadRecording(self, name):
        '''
            Get recording data from the savefile.
            
            @param name: a filename, aquired with ListRecordings
            @return: string containing the recording data
        '''
        return self._File2String(name)
    
    def _File2String(self, tarName):
        '''
            Read data from file in savefile to string
            
            @param tarName: filename in savefile
        '''
        data = ""
        if(self._SaveHasFile(tarName)):
            # open tarfile for reading
            tf = tarfile.open(self.savePath, 'r')
            if self._SaveHasFile(tarName):
                info = tf.getmember(tarName)
                tf.extract(info, os.path.join(self.programPath,'tmp'))
                data = open(os.path.join(self.programPath,'tmp',tarName), 'r').read()
                os.unlink(os.path.join(self.programPath,'tmp',tarName))
            else:
                print tarName, "not found in file"
            tf.close()
        return data
    
    def Delete(self):
        '''
            Delete saveFile, start over fresh.
            Useful when adding new dicom data to file, since it impossible to remove data from a tarfile
            Dont forget to re-add the XML.
            
            TODO: this method must fail if recordings are already added, changing the dicom data then won't
            make sense anyways.
        '''
        os.unlink(self.savePath)
    
    def Reset(self):
        '''
            Reset to new, blank temporary file
        '''
        self._ClearTemp()
        self._CreateTempFile()
    
    def IsTemp(self):
        ''' 
            @return: Are we saving to a temp file right now?
        '''
        return self.temp
        
    def _AddToSaveFile(self, path, arcname=None):
        '''
            Add a file or dir to the saveFile (tar archive)
            
            @param path: path the file you want to add
            @param arcname: alternative name to be used in the archive
        '''
        if os.path.exists(self.savePath):
            mode = 'a' # append, no compression
        else:
            mode = 'w' # write, no compression
        tf = tarfile.open(self.savePath, mode)
        tf.add(path, arcname)
        tf.close()
        
    def _SaveHasFile(self,path):
        '''
            Does the save file contain the file indicated by path?
            
            @return: true or false
        '''
        if not os.path.exists(self.savePath):
            return False
        tf = tarfile.open(self.savePath, 'r')
        try:
            info = tf.getmember(path)
            hasFile = True
        except KeyError:
            hasFile = False
        return hasFile
    
    def _ClearTemp(self):
        if(self.temp):
            if(os.path.exists(self.savePath)):
                os.unlink(self.savePath)
    
    def _CreateTempFile(self):
        self.temp = True # remember if we are writing to a temp file
        tmpfile = tempfile.mkstemp()
        os.close(tmpfile[0])
        os.unlink(tmpfile[1])
        self.savePath = tmpfile[1]
        print 'SAVEPATH:'+self.savePath


